package com.white.mybatis.dynamic;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.white.mybatis.dynamic.exceptions.DynamicMapperException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 动态表信息提取器
 * </p>
 *
 * @author huangzy
 * @since 2022/2/22
 */
public class DynamicTableExtractor {

    /**
     * sql语句操作
     */
    private final JdbcTemplate jdbcTemplate;

    /**
     * 需要映射的表名列表
     */
    private final String[] tableName;

    /**
     * 表名与字段映射
     */
    private Map<String, List<TableField>> tableFieldMap;

    /**
     * 获取动态表表信息提取器
     * @param jdbcTemplate jdbc
     * @param tableNames 需要提取的表列表
     */
    public DynamicTableExtractor(JdbcTemplate jdbcTemplate,String... tableNames){
        if (tableNames.length == 0) {
            throw new DynamicMapperException("至少需要一个表名");
        }
        this.tableName = tableNames;
        this.jdbcTemplate = jdbcTemplate;
        initTableFieldMap();
    }

    /**
     * 初始化表字段映射
     */
    public void initTableFieldMap(){
        this.tableFieldMap = Arrays.stream(tableName).collect(Collectors.toMap(item -> item,this::getTableField));
    }

    /**
     * 根据表名获取表字段信息
     * @param tableName 表名
     * @return
     */
    public List<TableField> getTableField(String tableName){
        List<TableField> fields;
        try {
            fields = jdbcTemplate.queryForList(MysqlKeywords.DESCRIBE.build(tableName))
                    .stream()
                    .map(item -> {
                        TableField tableField = new TableField();
                        tableField.setTableName(tableName);
                        tableField.setColumn(String.valueOf(item.get("Field")));
                        tableField.setProperty(StringUtils.underlineToCamel(tableField.getColumn()));
                        tableField.setPropertyView(StringUtils.underlineToCamel(tableName) + "_" + tableField.getProperty());
                        Object comment = item.get("Comment");
                        tableField.setComment(comment == null ? null : String.valueOf(comment));
                        return tableField;
                    }).collect(Collectors.toList());
        } catch (BadSqlGrammarException e) {
            throw new DynamicMapperException("表名称不存在: "+tableName,e);
        }
        return fields;
    }

    /**
     * 根据propertyView获取字段信息
     * @param propertyView 前端使用的字段格式,例如:
     *                     property,或者直接 tablename_property
     *                     如果多表建议使用 tablename_property
     *                     如果 propertyView 中没有查找到，则查找 property 字段匹配的值
     * @return 这个字段的详细信息
     */
    public TableField getTableFieldByProperty(String propertyView){
        for (List<TableField> tableFields : tableFieldMap.values()) {
            for (TableField tableField : tableFields) {
                if (tableField.getPropertyView().equals(propertyView)) {
                    return tableField;
                }
            }
        }
        //查找property
        for (List<TableField> tableFields : tableFieldMap.values()) {
            for (TableField tableField : tableFields) {
                if (tableField.getProperty().equals(propertyView)) {
                    return tableField;
                }
            }
        }
        return null;
    }

    /**
     * 根据Sql字段column获取字段信息
     * @param tableName 表名
     * @param column SQL使用的字段格式
     * @return 这个字段的详细信息
     */
    public TableField getTableFieldByColumn(String tableName , String column){
        for (TableField tableField : tableFieldMap.get(tableName)) {
            if (tableField.getColumn().equals(column)) {
                return tableField;
            }
        }
        return null;
    }

    /**
     * 重新加载数据库数据
     */
    public void reload(){
        initTableFieldMap();
    }

    /**
     * 根据表名获取字段列表
     * @param tableName 表名
     * @return
     */
    public List<TableField> getFieldsByTableName(String tableName) {
        return tableFieldMap.get(tableName);
    }
}
